package onlinebanking.server.modules;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;

import onlinebanking.constants.MSG;
import onlinebanking.exceptions.UserNotLoggedInException;
import onlinebanking.math.Polynomial;
import onlinebanking.network.Message;
import onlinebanking.security.threshold.Share;
import onlinebanking.security.threshold.ThresholdEngine;
import onlinebanking.server.ServerEngine;
import onlinebanking.server.objects.Announcement;
import onlinebanking.server.objects.AuthenticationCode;
import onlinebanking.server.objects.BankAccount;
import onlinebanking.server.objects.PersonalAccount;
import onlinebanking.server.objects.Transaction;

public class ConfirmTransactionModule extends Module {

	public ConfirmTransactionModule(ServerEngine se, Message message) {
		this.serverengine = se;
		this.message = message;
	}

	public Message handleRequest() {
		Message response = new Message();
		response.setMsgType(MSG.CONFIRM_TRANSACTION);

		if (!serverengine.isLoggedIn()) {
			response.setAsUserNotLoggedIn();
			return response;
		}
		try {
			int transactionid = message.getInt("transactionid");
			long PAC = message.getLong("PAC");
			long ConfirmPAC = message.getLong("ConfirmPAC");

			if (PAC != ConfirmPAC) {
				response.setSuccess(false);
				response.addAttribute("reason", "PACs dont match");
				return response;
			}
			
			response = recordAuthentication(transactionid, PAC);
			response.setMsgType(MSG.CONFIRM_TRANSACTION);
			return response;
				
//			Transaction transaction = new Transaction(transactionid);
//
//			if (!transaction.exists()) {
//				response.setSuccess(false);
//				response.addAttribute("reason", "No such transaction");
//				return response;
//			}
//
//			/*
//			 * ALGO on INSERT 1.insert on transaction confirmations, tacid =
//			 * personalaccountid and bankaccountid in tac table
//			 */
//			int personalaccountid = serverengine.getSession().getUserAccount()
//					.getpersonalaccountid();
//			int bankaccountid = transaction.getBankaccountid();
//
//			// check if already confirmed = same tacid and transactionid
//			int tacid = AuthenticationCode.getTACid(personalaccountid,
//					bankaccountid);
//			if (tacid < 0) {
//				response.setSuccess(false);
//				response.addAttribute("reason", "No Authentication Code entry");
//				return response;
//			}
//
//			boolean ownsTransaction = BankAccount.verifyOwnership(
//					personalaccountid, bankaccountid);
//			if (!ownsTransaction) {
//				response.setSuccess(false);
//				response.addAttribute("reason",
//						"Transaction does not belong to you");
//				return response;
//			}
//
//			// procede with insertion of confirmation
//			int insertedPK = transaction.insertConfirmation(tacid, PAC);
//			if (insertedPK < 0) {
//				response.setSuccess(false);
//				response.addAttribute("reason", "Confirmation not accepted");
//				return response;
//			} else {
//				response.setSuccess(true);
//				response.addAttribute("reason", "Confirmation received");
//			}
//
//			/*
//			 * ALGO on CHECKING 1. get confirmations for the given transactionid
//			 * -> transfonfirmations 2. check if enough confirmations >=
//			 * bankaccount.threshold 3. check if the confirmations are valid -
//			 * for every transconfirmationid, tacid, encryptedPAC, tacid.xindex
//			 */
//			boolean check = checkTransaction(transactionid);
//			if (check) {
//
//				boolean success = transaction.executeTransaction();
//				if (success) {
//					transaction.setTransactionAsDone();
//				}
//			}

		} catch (UserNotLoggedInException e) {
			response.setAsUserNotLoggedIn();
		}
		return response;
	}
	
	public Message recordAuthentication(int transactionid, long PAC ) throws UserNotLoggedInException{
		Message response = new Message();

		Transaction transaction = new Transaction(transactionid);

		if (!transaction.exists()) {
			response.setSuccess(false);
			response.addAttribute("reason", "No such transaction");
			return response;
		}

		/*
		 * ALGO on INSERT 1.insert on transaction confirmations, tacid =
		 * personalaccountid and bankaccountid in tac table
		 */
		int personalaccountid = serverengine.getSession().getUserAccount()
				.getpersonalaccountid();
		int bankaccountid = transaction.getBankaccountid();

		// check if already confirmed = same tacid and transactionid
		int tacid = AuthenticationCode.getTACid(personalaccountid,
				bankaccountid);
		if (tacid < 0) {
			response.setSuccess(false);
			response.addAttribute("reason", "No Authentication Code entry");
			return response;
		}

		boolean ownsTransaction = BankAccount.verifyOwnership(
				personalaccountid, bankaccountid);
		if (!ownsTransaction) {
			response.setSuccess(false);
			response.addAttribute("reason",
					"Transaction does not belong to you");
			return response;
		}

		// procede with insertion of confirmation
		int insertedPK = transaction.insertConfirmation(tacid, PAC);
		if (insertedPK < 0) {
			response.setSuccess(false);
			response.addAttribute("reason", "Confirmation not accepted. You have already sent your authentication for this transaction");
			return response;
		} else {
			response.setSuccess(true);
			response.addAttribute("reason", "Confirmation received");
		}
		
		boolean check = checkTransaction(transactionid);
		if (check) {

			boolean success = transaction.executeTransaction();
			if (success) {
				transaction.setTransactionAsDone();
				notifyOtherUsers(transactionid);
			}
		}
		
		return response;
	}

	/**
	 * 
	 * @param transactionid
	 *            The transaction to be checked
	 * @return returns whether a transaction received enough correct
	 *         confirmations
	 */
	private boolean checkTransaction(int transactionid) {

		System.out.println("ConfrimTransModule - checking trans");
		Transaction transaction = new Transaction(transactionid);

		if (!transaction.exists())
			return false;

		// CHECK VERIFY TRANSACTIONSTATUS

		int bankaccountid = transaction.getBankaccountid();
		int noOfConfirmations = AuthenticationCode
				.getConfirmationCount(transactionid);

		BankAccount bankaacount = new BankAccount(bankaccountid);
		if (!bankaacount.exists())
			return false;

		int threshold = bankaacount.getThreshold();

		System.out.println("CTM - confirmations:" + noOfConfirmations
				+ " req: " + threshold);
		// if not enough confirmations
		if (noOfConfirmations < threshold)
			return false;

		// Generate "shares";
		/*
		 * HOW TO GENERATE SHARES 1. get transconfirmationid, tacid,
		 * encryptedPAC from transconfirmations table 2. get tacid, xval, offset
		 * from tacs table
		 */
		Share shares[] = new Share[noOfConfirmations];

		ResultSet rs = AuthenticationCode.getConfirmations(transactionid);

		try {
			for (int i = 0; rs.next(); i++) {
				int transconfirmationid = rs.getInt("transconfirmationid");
				long PAC = rs.getLong("encryptedPAC");
				long xindex = rs.getLong("xval");
				int offset = rs.getInt("offset");

				shares[i] = new Share(xindex, PAC + offset);

			}

			ThresholdEngine thresholdengine = new ThresholdEngine();
			Polynomial p = thresholdengine.LagrangeInterpolate(shares);
			long TAC = p.evaluatePoly(0);

			boolean valid = AuthenticationCode.AuthenticateTAC(bankaccountid,
					TAC);
			
			return valid;
		} catch (SQLException e) {
			e.printStackTrace();
			return false;
		}

	}

	private void notifyOtherUsers(int transactionid){
		System.out.println("notifying other users");
		//detetmine other users;
		try {
			int accountowners[] = this.serverengine.getSession().getActiveBankAccount().getAccountOwners();
	
			int personalaccountid = this.serverengine.getSession().getUserAccount().getpersonalaccountid();
			
			Date now = new Date();
			String notification = "A transaction was procesed on "+ now + " with transaction id " + transactionid;
			
			for(int i = 0; i<accountowners.length; i++){
				Announcement.postPersonalAnnouncement(accountowners[i], personalaccountid, notification);
			}
			
		} catch (UserNotLoggedInException e) {
		}
		
	}
}
